import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.LinkedList;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Main {
  
  JFrame window;
  boardPanel gamePanel;
  Board board;
  GameState gameState;
  
  public Main() {

  }
  
  public void initial(){
    
    board = new Board(this);
    window = new JFrame();
    
    //initialize global variables
    initGame();
    
    gamePanel = new boardPanel(this);
    window.setSize(1000, 600);
    window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
    window.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        int flag = JOptionPane.showConfirmDialog(window, "Really exit?", "Exit Game", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
        if (JOptionPane.YES_OPTION == flag) {
                 //delete its own player
          System.exit(0);
        } else {
          return;
        }
      }
     });
    window.setVisible(true);
    
  }
  
  public void initGame(){
	  BoardGame.initializeBoard(this);
	  
	  int numPlayers;
	  boolean[] activePlayers;
	
	  gameState = new GameState();
	  
	  //initialize active players
	  numPlayers = board.getPlayer().length;
	  activePlayers = new boolean[numPlayers];
	  for(int i = 0; i < numPlayers; i ++){
		  activePlayers[i] = true;
	  }
	  
	  gameState.setNumPlayers(numPlayers);
	  gameState.setNumTurns(0);
	  gameState.setNumRounds(0);
	  gameState.setActivePlayer(activePlayers);
	  int currentPlayer = 0;
	  Player[] players = board.getPlayer();
	  if(players.length > 0){
		  while(players[currentPlayer].getDelay() > 0) {
			    currentPlayer = (currentPlayer + 1) % players.length;
			  }
		  gameState.setCurrentPlayer(currentPlayer);
		  gameState.setRunning(true);
	  } 
  }
  
  public void execTurn(){
	  
	  int num = 0;
	  Dice[] dice;
	  int currentPlayer;
	  
	  int numCell = 0;
	  
	  //the residue of dice numbers divide number of cells 
	  int steps = 0;
	  
	  //get numbers of dice
	  dice = board.getDice();
	  for(int i = 0; i < dice.length; i ++){
		  num = num + dice[i].getNumber();
	  }
	  
	  //get current player
	  currentPlayer = gameState.getCurrentPlayer();	  
	  
	  //get number of cells
	  numCell = 2 * board.getHeight() + 2 * board.getWidth() - 4;
	  
	  //move players
	  steps = num % numCell;
	  Player currPlayer = board.getPlayer()[currentPlayer];
	  currPlayer.move(steps);
	  
	  BoardGame.InitializeCells(this, currPlayer.getLocationX(), currPlayer.getLocationY());
	  
	  updateGameState();
	  gamePanel.iPanel.updatePlayers();
	  checkGameOver();
	  
	  gamePanel.iPanel.updateInfo();
  }
  
  //update GameState object
  public void updateGameState(){
	  
	  int currentPlayer;
	  int previousPlayer;
	  int numTurns;
	  int numRounds;
	  boolean[] activePlayers;
	  //number of active players
	  int numActive = 0;
	  
	  //get number of active players;
	  activePlayers = gameState.getActivePlayer();
	  for(int i = 0; i < activePlayers.length; i++){
		  if(activePlayers[i]){
			  numActive ++;
		  }
	  }
	  	  
	  //set current player to be next player in turn
	  previousPlayer = gameState.getCurrentPlayer();
	  currentPlayer = previousPlayer;
	  Player[] players = board.getPlayer();
	  int prevDelay = players[previousPlayer].getDelay();
	  if(prevDelay < 0) {
	    players[currentPlayer].setDelay(prevDelay + 1);
	  }
	  else {
  	  currentPlayer = (currentPlayer + 1) % numActive;
  	  while(true) {
  	    if(activePlayers[currentPlayer]) {
  	      Player current = players[currentPlayer];
  	      int delay = current.getDelay();
  	      if(delay > 0) {
  	        current.setDelay(delay - 1);
  	        currentPlayer = (currentPlayer + 1) % numActive;
  	      }
  	      else {
  	        break;
  	      }
  	    }
  	    else {
  	      currentPlayer = (currentPlayer + 1) % numActive;
        }
  	  }
	  }
	  
	  gameState.setCurrentPlayer(currentPlayer);
	  
	  //update number of turns
	  numTurns = gameState.getNumTurns() + 1;
	  gameState.setNumTurns(numTurns);
	  
	  //update number of rounds
	  if(currentPlayer <= previousPlayer){
		  numRounds = gameState.getNumRounds();
		  gameState.setNumRounds(numRounds + 1);
	  }
	  
  }
  
  public void checkGameOver(){
	  
	  Player[] winner = BoardGame.Winner(this);
	  boolean isWinner = false;
	  if(winner != null){
		  String winStr = "Winners: ";
		  for(int i = 0; i < winner.length; i ++){
			  if(winner[i] != null) {
			    winStr += winner[i].getName() + ", ";
			    isWinner = true;
		    }
		  }
		  if(isWinner) endGame(winStr.substring(0, winStr.length()-2));
	  }
	  
	  if(BoardGame.GameOver(this)){
		  endGame("Game Over!");
	  }
  }
  
  public void go() {
    window.setTitle(board.getTitle());
    window.add(gamePanel);
    window.setVisible(true);
    window.validate();
    gamePanel.gPanel.requestFocusInWindow();
    gamePanel.startGame();
  }
  
  public void Delay(Player p, int value){
		p.setDelay(p.getDelay() + value);
	}
	
	public void Change(Player p, int value){
		p.setPoints(p.getPoints() + value);
	}
	
	public void Direction(Player p, boolean value){
		p.setDirection(value);
	}
	
	public void GoTo(Player p, int x, int y){
		  boolean err = p.setLocation(x, y);
		  if(!err) endGame("ERROR: GoTo: Invalid Location: (" + x + ", " + y + ")");
	}
	
	public void endGame(String msg) {
	  JOptionPane.showMessageDialog(null, msg, "Game Over", JOptionPane.INFORMATION_MESSAGE);
	  System.out.println("Game Over");
	  gameState.setRunning(false);
	}
	
	public static void main(String[] args) {
      Main game = new Main();
      game.initial();
      game.go();
  }
}